﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using NGE;
using NGE.Net;

using MH;

namespace MH.Server
{

    class ServerComponent : Component
    {
        public ServerComponent(Game g)
            : base("ServerComponent", g)
        {
            server = new NGE.Net.Server();
            server.OnClientConnected += new SessionEvent(server_OnClientConnected);
            server.OnClientDisconnected += new SessionEvent(server_OnClientDisconnected);
            server.OnReceived += new SessionEvent(server_OnDataReceived);
               
            createClientFileList();

            pcs = new PCs();
        }

        string GetMD5(string fileName)
        {
            string hashMD5 = string.Empty;

            //检查文件是否存在，如果文件存在则进行计算，否则返回空值
            if (System.IO.File.Exists(fileName))
            {
                using (System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    //计算文件的MD5值
                    System.Security.Cryptography.MD5 calculator = System.Security.Cryptography.MD5.Create();
                    Byte[] buffer = calculator.ComputeHash(fs);
                    calculator.Clear();
                    //将字节数组转换成十六进制的字符串形式
                    StringBuilder stringBuilder = new StringBuilder();
                    for (int i = 0; i < buffer.Length; i++)
                    {
                        stringBuilder.Append(buffer[i].ToString("x2"));
                    }
                    hashMD5 = stringBuilder.ToString();
                }//关闭文件流

            }//结束计算

            return hashMD5;
        }

        List<NFile> fileList;
        void addfile(string filename)
        {
            NFile f = new NFile();
            f.Name = filename;
            //f.Version = System.Diagnostics.FileVersionInfo.GetVersionInfo(filename).FileVersion;
            f.Version = GetMD5(filename);
            fileList.Add(f);
        }

        void createClientFileList()
        {
            fileList = new List<NFile>();

            string[] fls = System.IO.File.ReadAllLines("releaselist.txt");

            foreach (string str in fls)
            {
                addfile(str);
            }

            string[] lines = new string[fileList.Count * 2];
            int i = 0;
            foreach (NFile nfile in fileList)
            {
                lines[i++] = nfile.Name;
                lines[i++] = nfile.Version;
                File.Copy(nfile.Name, "c:\\inetpub\\wwwroot\\" + nfile.Name, true);
            }

            File.WriteAllLines("c:\\inetpub\\wwwroot\\fl.txt", lines);            
        }

        public PCs pcs;

        void server_OnClientDisconnected(object sender, object arg)
        {
            Client client = (Client)sender;

            Character pc = (Character)Util.Clone(pcs.GetPC(client.Handle));
            boardcast(client, "offline " + pc.Name);
            pcs.Del(client.Handle);
            AppendLog(this, DateTime.Now.ToString("HH:mm:ss.fff") + ": " + client.RemoteAddress + " 已登出");
        }

        void server_OnClientConnected(object sender, object arg)
        {
            Client client = (Client)sender;
            AppendLog(this, DateTime.Now.ToString("HH:mm:ss.fff") + ": " + client.RemoteAddress + " 已登入");
        }

        public delegate void LogEvent(object sender, string text);
        public event LogEvent AppendLog;

        
        NGE.Net.Server server;

        public void Start(int port)
        {
            server.Start(port);
        }
        public void Stop()
        {
            server.Stop();
        }

        void server_OnDataSent(object sender, object arg)
        {
            //append(e.Session, "传输完成");
        }

        void server_OnDataReceived(object sender, object arg)
        {
            Client client = (Client)sender;
            byte[] data = (byte[])arg;
            CharacterEventArgs ea = (CharacterEventArgs)Util.Deserialize(Util.Decompress(data));
            

            if (ea.Act == CharacterActs.TEST)
            {
                if (ea.Arg is double)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.TEST, ea.Arg);
                    server.Send(client, Util.Compress(Util.Serialize(pcea)));
                }
            }
            else if (ea.Act == CharacterActs.GETPC)
            {
                if (ea.Arg is int)
                {
                    Character chr = new Character();
                    chr.Name = "PC-" + client.Handle;
                    chr.Avatar.GetData(game.Option.ImagePath + "sprite\\mh-chr-" + Util.Roll(5).ToString("d3") + ".png");
                    chr.AvatarSize = new System.Drawing.Size(16, 16);
                    chr.Handle = client.Handle;

                    send_pc_to(chr, client);
                    AppendLog(this, DateTime.Now.ToString("HH:mm:ss.fff") + ": " + client.RemoteAddress + " 请求下载人物数据");
                }
                //else if (ea.Arg is string)
                //{
                //    Character chr = OPCs[getOPC(e.Session.Handle)];

                //    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, chr);

                //    server.Send(e.Session, pcea);

                //    //append(e.Session, "人物数据[ " + ea.Arg.ToString() + " ]开始传出");
                //}
            }
            else if (ea.Act == CharacterActs.GETScene)
            {
                //append(e.Session, "请求传输场景文件[ " + ea.Arg.ToString() + " ]");

                Scene scn = ((SceneComponent)game.GetComponent("SceneCOM")).LoadScene(ea.Arg.ToString());
                scn.Name = ea.Arg.ToString();
                //append(e.Session, "场景文件[ " + ea.Arg.ToString() + " ]已载入");

                CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETScene, scn);
                server.Send(client, Util.Compress(Util.Serialize(pcea)));
                //append(e.Session, "场景文件[ " + ea.Arg.ToString() + " ]开始传出");

            }
            else if (ea.Act == CharacterActs.GETOPC)
            {
                if (ea.Arg == null)
                {
                    send_opcs_to(client);
                    AppendLog(this, DateTime.Now.ToString("HH:mm:ss.fff") + ": " + client.RemoteAddress + " 请求下载同场景所有人物数据");
                }
                //else if (ea.Arg is string)
                //{
                //    string name = (string)ea.Arg;
                //    int i = getOPCIndex(name);
                //    if (i < 0)
                //    {
                //        return;
                //    }
                //    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, OPCs[i]);
                //    server.Send(client, Util.Compress(Util.Serialize(pcea)));
                //    AppendLog(this, DateTime.Now.ToString("HH:mm:ss.fff") + ": " + client.RemoteAddress + " 请求下载[ " + name + " ]的人物数据");
                //}
            }
            else if (ea.Act == CharacterActs.SETPC)
            {
                Character pc = pcs.GetPC(client.Handle);
                if (ea.Arg is Character)
                {
                    Character newpc = (Character)ea.Arg;

                    if (pc != null)
                    {
                        if (pc.InSceneName != newpc.InSceneName)
                        {
                            //boardcast(client, pc.SceneInfo);
                            pcs.Del(client.Handle);
                        }
                    }

                    pcs.Ins(newpc, client.Handle);

                    AppendLog(this, DateTime.Now.ToString("HH:mm:ss.fff") + ": " + client.RemoteAddress + " 人物数据已更新");
                    boardcast(client, newpc);
                }
                else if (ea.Arg is Datagram.PlayerCharacterSceneInfo)
                {
                    Datagram.PlayerCharacterSceneInfo pcsi = (Datagram.PlayerCharacterSceneInfo)ea.Arg;
                    pc.SceneInfo = pcsi;
                }
                else if (ea.Arg is Datagram.PlayerCharacterMoveInfo)
                {
                    Datagram.PlayerCharacterMoveInfo pcmi = (Datagram.PlayerCharacterMoveInfo)ea.Arg;
                    boardcast(client, pcmi);
                    //AppendLog(this, DateTime.Now.ToString("HH:mm:ss.fff") + ": " + client.RemoteAddress + " 人物场景数据已更新");
                }
                else if (ea.Arg is Datagram.PlayerCharacterBattleInfo)
                {
                    Datagram.PlayerCharacterBattleInfo pcbi = (Datagram.PlayerCharacterBattleInfo)ea.Arg;
                    boardcast(client, pcbi);
                }
                else if (ea.Arg is Datagram.PlayerCharacterSayInfo)
                {
                    Datagram.PlayerCharacterSayInfo pcsay = (Datagram.PlayerCharacterSayInfo)ea.Arg;
                    boardcast(client, pcsay);
                }
            }
        }




        void boardcast(Client client, string cmd)
        {
            List<Character> opcs = pcs.GetPCsInSameScene(client.Handle);
            if (opcs == null)
            {
                return;
            }
            for (int i = 0; i < opcs.Count; i++)
            {
                Character opc = opcs[i];
                if (opc.Handle != client.Handle)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, cmd);
                    server.Send(opc.Handle, Util.Compress(Util.Serialize(pcea)));
                }
            }
        }
        void boardcast(Client client, Datagram.PlayerCharacterSceneInfo pcsi)
        {
            List<Character> opcs = pcs.GetPCsInSameScene(pcsi.InSceneName);
            if (opcs == null)
            {
                return;
            }
            for (int i = 0; i < opcs.Count; i++)
            {
                Character opc = opcs[i];
                if (opc.Handle != client.Handle)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, pcsi);
                    server.Send(opc.Handle, Util.Compress(Util.Serialize(pcea)));
                }
            }
        }
        void boardcast(Client client, Datagram.PlayerCharacterMoveInfo pcmi)
        {
            List<Character> opcs = pcs.GetPCsInSameScene(client.Handle);
            if (opcs == null)
            {
                return;
            }
            for (int i = 0; i < opcs.Count; i++)
            {
                Character opc = opcs[i];

                if (opc.Handle != client.Handle)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, pcmi);
                    server.Send(opc.Handle, Util.Compress(Util.Serialize(pcea)));
                }
            }
        }
        void boardcast(Client client, Datagram.PlayerCharacterBattleInfo pcbi)
        {
            List<Character> opcs = pcs.GetPCsInSameScene(client.Handle);
            if (opcs == null)
            {
                return;
            }
            for (int i = 0; i < opcs.Count; i++)
            {
                Character opc = opcs[i];

                if (opc.Handle != client.Handle)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, pcbi);
                    server.Send(opc.Handle, Util.Compress(Util.Serialize(pcea)));
                }
            }
        }
        void boardcast(Client client, Datagram.PlayerCharacterSayInfo pcsay)
        {
            List<Character> opcs = pcs.GetPCsInSameScene(client.Handle);
            if (opcs == null)
            {
                return;
            }
            for (int i = 0; i < opcs.Count; i++)
            {
                Character opc = opcs[i];

                if (opc.Handle != client.Handle)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, pcsay);
                    server.Send(opc.Handle, Util.Compress(Util.Serialize(pcea)));
                }
            }
        }
        void boardcast(Client client, Character pc)
        {
            List<Character> opcs = pcs.GetPCsInSameScene(client.Handle);
            if (opcs == null)
            {
                return;
            }
            for (int i = 0; i < opcs.Count; i++)
            {
                Character opc = opcs[i];

                if (opc.Handle != client.Handle)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, pc);
                    server.Send(opc.Handle, Util.Compress(Util.Serialize(pcea)));
                }
            }
        }
        //下线
        //void boardcast(Client client, string name)
        //{
        //    List<Character> opcs = pcs.GetPCsInSameScene(client.Handle);
        //    if (opcs == null)
        //    {
        //        return;
        //    } 
        //    foreach (Character opc in opcs)
        //    {
        //        if (opc.Handle != client.Handle)
        //        {
        //            CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, name);
        //            server.Send(client, Util.Compress(Util.Serialize(pcea)));
        //        }
        //    }
        //}
        void send_opcs_to(Client client)
        {
            List<Character> opcs = pcs.GetPCsInSameScene(client.Handle);
            if (opcs == null)
            {
                return;
            } 
            foreach (Character opc in opcs)
            {
                if (opc.Handle != client.Handle)
                {
                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETOPC, opc);
                    server.Send(client, Util.Compress(Util.Serialize(pcea)));
                }
            }
        }
        void send_pc_to(Character pc, Client client)
        {
            CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.SETPC, pc);
            byte[] data = Util.Compress(Util.Serialize(pcea));
            server.Send(client, data);
        }
    }

    class SCNPCs
    {
        public string Name;
        public List<Character> Items = new List<Character>();

        public SCNPCs(string name)
        {
            Name = name;
            Items = new List<Character>();
        }

        public int GetIndex(int handle)
        {
            for (int i = 0; i < Items.Count; i++)
            {
                if (handle == Items[i].Handle)
                {
                    return i;
                }
            }
            return -1;
        }
        public int GetIndex(string name)
        {
            for (int i = 0; i < Items.Count; i++)
            {
                if (name == Items[i].Name)
                {
                    return i;
                }
            }
            return -1;
        }

        public void Ins(Character pc, int handle)
        {
            pc.Handle = handle;
            Items.Add(pc);
        }

        public void Del(string name)
        {
            int i = GetIndex(name);
            Items.RemoveAt(i);
        }
        public int Count
        {
            get
            {
                return Items.Count;
            }
        }

    }

    class PCs
    {
        public List<SCNPCs> Items = new List<SCNPCs>();
        public PCs()
        {
            Items = new List<SCNPCs>();
        }
        int getSCNIndex(string scnName)
        {
            for (int i = 0; i < Items.Count; i++)
            {
                if (scnName == Items[i].Name)
                {
                    return i;
                }
            }
            return -1;
        }
        void getSCNPCIndex(string pcname, out int Sindex, out int Pindex)
        {
            for (int i = 0; i < Items.Count; i++)
            {
                int j = Items[i].GetIndex(pcname);
                if (j > -1)
                {
                    Sindex = i;
                    Pindex = j;
                    return;
                }
            }
            Sindex = Pindex = -1;
        }
        void getSCNPCIndex(int handle, out int Sindex, out int Pindex)
        {
            for (int i = 0; i < Items.Count; i++)
            {
                int j = Items[i].GetIndex(handle);
                if (j > -1)
                {
                    Sindex = i;
                    Pindex = j;
                    return;
                }
            }
            Sindex = Pindex = -1;
        }

        public void Ins(Character pc, int handle)
        {
            int i = getSCNIndex(pc.InSceneName);
            if (i < 0)
            {
                Items.Add(new SCNPCs(pc.InSceneName));
                i = Items.Count - 1;
            }
            int j = Items[i].GetIndex(handle);
            if (j < 0)
            {
                Items[i].Ins(pc, handle);
            }
            else
            {
                Items[i].Items[j] = pc;
            }
        }
        public void Del(int handle)
        {
            int i = 0;
            int j = 0;
            getSCNPCIndex(handle, out i, out j);
            if (i < 0)
            {
                return;
            }
            if (j < 0)
            {
                return;
            }
            Items[i].Items.RemoveAt(j);
        }
        public List<Character> GetPCsInSameScene(int handle)
        {
            int i = 0;
            int j = 0;
            getSCNPCIndex(handle, out i, out j);
            if (i < 0)
            {
                return null;
            }
            if (j < 0)
            {
                return null;
            }
            return Items[i].Items;
        }
        public List<Character> GetPCsInSameScene(string scnName)
        {
            int i = getSCNIndex(scnName);
            return Items[i].Items;
        }
        public Character GetPC(int handle)
        {
            int i = 0;
            int j = 0;
            getSCNPCIndex(handle, out i, out j);
            if (i < 0)
            {
                return null;
            }
            if (j < 0)
            {
                return null;
            }
            return Items[i].Items[j];
        }


    }

}
